package com.noyes4j.common.utils.security;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.MessageDigest;
import java.util.Random;

/**
 * Md5加密方法
 * 
 * @author zhaoweiqin
 */
public class Md5Utils
{
    private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);

    private static byte[] md5(String s)
    {
        MessageDigest algorithm;
        try
        {
            algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(s.getBytes("UTF-8"));
            byte[] messageDigest = algorithm.digest();
            return messageDigest;
        }
        catch (Exception e)
        {
            log.error("MD5 Error...", e);
        }
        return null;
    }

    private static final String toHex(byte hash[])
    {
        if (hash == null)
        {
            return null;
        }
        StringBuffer buf = new StringBuffer(hash.length * 2);
        int i;

        for (i = 0; i < hash.length; i++)
        {
            if ((hash[i] & 0xff) < 0x10)
            {
                buf.append("0");
            }
            buf.append(Long.toString(hash[i] & 0xff, 16));
        }
        return buf.toString();
    }

    public static String hash(String s)
    {
        try
        {
            return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8");
        }
        catch (Exception e)
        {
            log.error("not supported charset...{}", e);
            return s;
        }
    }



    /**
     * API签名
     *
     * @param signStr
     * @param timestamp
     * @return
     */
    public static synchronized String generateSigNew(String signStr, String timestamp, String appId) {
        String salt = "%^q0&p3epm3r@rb@";


        int[] ints = {1, 1, 2, 3, 5, 8, 13, 21};
        int intsLength = ints.length;

        try {
            //连接salt和timestamp生成MD5小写32位字符串，得到_code1
            String str = salt + timestamp;
            String code1 = MD5(str);
            System.out.println("+++++++ str=" + str + ", code1=" + code1);

            //对_code1取费波拉契线序列 8位
            StringBuilder code2Builder = new StringBuilder();
            for (int i = 0; i < intsLength; i++) {
                code2Builder.append(code1.charAt(ints[i]));
            }
            System.out.println("+++++++ code2Builder=" + code2Builder);

            //连接_code2Builder和salt，再次生MD5小写32位字符串，得到_code3
            String secondStr = signStr + code2Builder.append(salt).append(timestamp).toString();
            String code3 = MD5(secondStr);
            System.out.println("+++++++ secondStr:" + secondStr+"  len:"+secondStr.length());
            System.out.println("+++++++ code3:" + code3);

            //对_code3取费波拉契线序列8位
            StringBuilder sigBuilder = new StringBuilder();
            for (int i = 0; i < intsLength; i++) {
                sigBuilder.append(code3.charAt(ints[i]));
            }

            return sigBuilder.toString();

        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }


    /**
     * 按照既定规则进行MD5加密
     *
     * @param s
     * @return
     */
    public final static synchronized String MD5(String s) {
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] btInput = s.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");

            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式

            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }

            return new String(str).toLowerCase();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 按照既定规则进行BASE64解密
     *
     * @param password
     * @return
     */
    public static synchronized String decrypt(String password) {
        if (password == null) {
            return null;
        }
        try {
            // 使用 '-'和'_' 替换为 '+'和'/';
            password = password.replace('-', '+').replace('_', '/');
            StringBuilder _strBuilder1 = new StringBuilder(password);
            int _lastLong = password.length() % 4;
            for (int i = 0; i < _lastLong; i++) {
                _strBuilder1.append("=");
            }
            password = _strBuilder1.toString();
            System.out.println("加密前password:" + password);
            // 先取得字符串长度(strlen) ==> 模4求余(%) ==> 右侧补齐余数长度的字符串不足长度用 '=' 进行补充 ==> base64 解码;
            password = new String(Base64.decodeBase64(password.getBytes()));
            System.out.println("加密后password:" + password);
            // 从右侧取4个字符, 字符顺序不变;
            // 123456789 ==> 6789
            String _part1 = password.substring(password.length() - 4);
            System.out.println("_part1:" + _part1);
            // 从左侧第0个字符开始, 去除右侧的4个字符;
            // 123456789 ==> 12345
            String _part2 = password.substring(0, password.length() - 4);
            System.out.println("_part2:" + _part2);
            // _part1 和 _part2 拼接在一起 ==> 使用 '-'和'_' 替换为 '+'和'/';
            password = (_part1 + _part2).replace('-', '+').replace('_', '/');
            _lastLong = password.length() % 4;

            StringBuilder _strBuilder2 = new StringBuilder(password);
            for (int i = 0; i < _lastLong; i++) {
                _strBuilder2.append("=");
            }
            password = _strBuilder2.toString();
            // 重复第二步的逻辑
            password = new String(Base64.decodeBase64(password.getBytes()));
            System.out.println("最后的password:" + password);
            // 返回结果
            return password;

        } catch (Exception e) {
            // TODO: handle exception
            return null;
        }
    }

    /**
     * 按照既定规则进行BASE64 加密
     *
     * @param s
     * @return
     */
    public static synchronized String encrypt(String s) {
        if (s == null) {
            return null;
        }
        if (s.length() < 4) {
            for (int i = 0; i < 4 - s.length(); i++) {
                s += "x";
            }
        }
        try {
            String _s = new String(Base64.encodeBase64(s.getBytes()));
            System.out.println("_s:" + _s);
            _s = _s.replace('+', '-').replace('/', '_');
            System.out.println("替换后：_s:" + _s);
            for (int i = 0; i < _s.length(); i++) {
                int _lastSpaceIndex = _s.lastIndexOf(' ');
                if (_lastSpaceIndex >= 0
                        && _lastSpaceIndex == _s.length() - 1) {
                    _s = _s.substring(0, _lastSpaceIndex);
                }

                int _lastIndex = _s.lastIndexOf('=');
                if (_lastIndex >= 0 && _lastIndex == _s.length() - 1) {
                    _s = _s.substring(0, _lastIndex);
                }
            }
            System.out.println("_s:" + _s);
            String _part1 = _s.substring(0, 4);
            System.out.println("_part1:" + _part1);
            String _part2 = _s.substring(4);
            System.out.println("_part2:" + _part2);
            _s = _part2 + _part1;
            _s = new String(Base64.encodeBase64(_s.getBytes())).replace('+', '-').replace('/', '_');

            for (int i = 0; i < _s.length(); i++) {
                int _lastSpaceIndex = _s.lastIndexOf(' ');
                if (_lastSpaceIndex >= 0
                        && _lastSpaceIndex == _s.length() - 1) {
                    _s = _s.substring(0, _lastSpaceIndex);
                }

                int _lastIndex2 = _s.lastIndexOf('=');
                if (_lastIndex2 >= 0 && _lastIndex2 == _s.length() - 1) {
                    _s = _s.substring(0, _lastIndex2);
                }
            }

            return _s;

        } catch (Exception e) {
            e.printStackTrace();
            // TODO: handle exception
            return null;
        }
    }

    /**
     * 获取密码salt
     *
     * @param length
     * @param clear
     * @return
     */
    public static synchronized String getSalt(Integer length, Boolean clear) {
        //给两个参数复制 如果传的都是null
        length = length == null ? 10 : length;//默认10
        clear = clear == null ? false : clear;//默认false

        String _str1 = "abcdefghijklmnopqrstuvwxyz0123456789";
        String _str2 = "abcdefghjkmnpqrstuvwxyz123456789";
        String _str = clear ? _str2 : _str1;
        int _strLen = _str.length();
        StringBuilder _temp = new StringBuilder();
        Random _random = new Random();
        for (int i = 0; i < length; i++) {
            _temp.append(_str.charAt(_random.nextInt(_strLen)));
        }
        return _temp.toString();
    }

    /**
     * 保存到数据库的密码加密算法
     *
     * @param password
     * @param salt
     * @return
     */
    public static synchronized String encryptPassword(String password, String salt) {
        String _md5pass = MD5(MD5(salt + password + salt));
        return _md5pass;
    }

}
